﻿using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Casamiel.API.Infrastructure.Exceptions;
using FluentValidation;
using MediatR;

namespace Casamiel.API.Infrastructure.Behaviors
{
    /// <summary>
    /// Validator behavior.
    /// </summary>
    public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    {
        private readonly IValidator<TRequest>[] _validators;
       /// <summary>
       /// 
       /// </summary>
       /// <param name="validators">Validators.</param>
        public ValidatorBehavior(IValidator<TRequest>[] validators) => _validators = validators;
        /// <summary>
        /// Handle the specified request, cancellationToken and next.
        /// </summary>
        /// <returns>The handle.</returns>
        /// <param name="request">Request.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name="next">Next.</param>
        public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
        {
            var failures = _validators
                .Select(v => v.Validate(request))
                .SelectMany(result => result.Errors)
                .Where(error => error != null)
                .ToList();

            if (failures.Any())
            {

                throw new CasamielDomainException(
                    $"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
            }

            var response = await next().ConfigureAwait(false);
            return response;
        }
    }
}
